using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BitMango;
using BitMango.Diagnostics;
using UnityEngine;
using UnityEngine.UI;

namespace BMCommon
{
    public static class BMTool
    {

        public static float GetScreenDPI()
        {
            float num = Screen.dpi;
            if (num == 0f)
            {
                UnityEngine.Debug.Log("This device is not supported. Default DPI Return.");
                num = 160f;
            }
            if (Application.platform == RuntimePlatform.Android)
            {
            }
            return num;
        }

        public static float ConvertPixelToMillimeter(Camera camera, float pixel = 1f)
        {
            Debugger.Assert(camera != null, "Camera is null");
            Debugger.Assert(camera.orthographic, "Camera is not orthographic");
            if (camera == null)
            {
                return -1f;
            }
            float screenDPI = BMTool.GetScreenDPI();
            float num = screenDPI / 25.4f;
            return pixel / num;
        }

        public static float ConvertMillimeterToWorldLength(Camera camera, float millimeter = 1f)
        {
            Debugger.Assert(camera != null, "Camera is null");
            Debugger.Assert(camera.orthographic, "Camera is not orthographic");
            if (camera == null)
            {
                return -1f;
            }
            float screenDPI = BMTool.GetScreenDPI();
            float num = screenDPI / 25.4f;
            return BMTool.ConvertPixelToWorldLength(camera, 1f) * num * millimeter;
        }

        public static float ConvertPixelToWorldLength(Camera camera, float pixel = 1f)
        {
            Debugger.Assert(camera != null, "Camera is null");
            Debugger.Assert(camera.orthographic, "Camera is not orthographic");
            if (camera == null)
            {
                return -1f;
            }
            tk2dCamera component = camera.gameObject.GetComponent<tk2dCamera>();
            float num = (float)camera.pixelHeight;
            if (component != null)
            {
                return component.ScreenExtents.height / num * pixel;
            }
            return camera.orthographicSize * 2f / num * pixel;
        }

        public static float GetRateUGUICanvasPixel(CanvasScaler scaler)
        {
            Debugger.Assert(scaler != null, "BMTool.GetRateUGUICanvasPixel : canvas scaler value is null");
            Debugger.Assert(scaler.matchWidthOrHeight == 1f, "BMTool.GetRateUGUICanvasPixel : canvas.matchWidthOrHeight is not 1f.");
            float num = (float)Screen.height;
            float num2 = scaler.referenceResolution.y;
            if (Screen.height < Screen.width)
            {
                num = (float)Screen.width;
                num2 = scaler.referenceResolution.x;
            }
            return num / num2;
        }

        public static Mesh CreateLineMesh(Vector3[] pos, float lineWidth, float uvScale, bool flipY, bool closed, LineOffset Loffset = LineOffset.Centered)
        {
            Debugger.Assert(pos.Length > 1, "BMTool.CreateLineMesh pos lenth fail : " + pos.Length);
            int num = pos.Length;
            int[] array = new int[(num - 1) * 6];
            for (int i = 0; i < num - 1; i++)
            {
                array[i * 6] = i * 2;
                array[i * 6 + 1] = (i + 1) * 2 + 1;
                array[i * 6 + 2] = (i + 1) * 2;
                array[i * 6 + 3] = i * 2;
                array[i * 6 + 4] = i * 2 + 1;
                array[i * 6 + 5] = (i + 1) * 2 + 1;
            }
            float[] array2 = new float[num];
            float num2 = 0f;
            for (int j = 1; j < pos.Length; j++)
            {
                num2 += (pos[j - 1] - pos[j]).magnitude;
                array2[j] = num2;
            }
            float num3 = (float)((int)(num2 + 0.5f)) * uvScale;
            for (int k = 0; k < pos.Length; k++)
            {
                array2[k] = array2[k] * num3 / num2;
            }
            Vector3[] array3 = new Vector3[num * 2];
            Vector2[] array4 = new Vector2[num * 2];
            Vector3 a = Vector3.zero;
            Vector3 back = Vector3.back;
            if (closed)
            {
                Vector3 lhs = pos[pos.Length - 1] - pos[pos.Length - 2];
                a = Vector3.Cross(lhs, back).normalized;
            }
            int num4 = 0;
            for (int l = 0; l < pos.Length - 1; l++)
            {
                Vector3 vector = pos[l];
                Vector3 vector2 = pos[l + 1];
                Vector3 lhs2 = vector2 - vector;
                Vector3 normalized = Vector3.Cross(lhs2, back).normalized;
                Vector3 b = Vector3.zero;
                if (Loffset != LineOffset.Centered)
                {
                    if (Loffset != LineOffset.Inner)
                    {
                        if (Loffset == LineOffset.Outer)
                        {
                            b = (a + normalized).normalized * lineWidth;
                            array3[num4 * 2] = vector;
                            array3[num4 * 2 + 1] = vector + b;
                        }
                    }
                    else
                    {
                        b = (a + normalized).normalized * lineWidth;
                        array3[num4 * 2] = vector - b;
                        array3[num4 * 2 + 1] = vector;
                    }
                }
                else
                {
                    b = (a + normalized).normalized * lineWidth * 0.5f;
                    array3[num4 * 2] = vector - b;
                    array3[num4 * 2 + 1] = vector + b;
                }
                if (!flipY)
                {
                    array4[num4 * 2] = new Vector2(array2[l], 0f);
                    array4[num4 * 2 + 1] = new Vector2(array2[l], 1f);
                }
                else
                {
                    array4[num4 * 2] = new Vector2(array2[l], 1f);
                    array4[num4 * 2 + 1] = new Vector2(array2[l], 0f);
                }
                if (l == pos.Length - 2)
                {
                    if (Loffset != LineOffset.Centered)
                    {
                        if (Loffset != LineOffset.Inner)
                        {
                            if (Loffset == LineOffset.Outer)
                            {
                                array3[num4 * 2 + 2] = vector2;
                                array3[num4 * 2 + 3] = vector2 + normalized * lineWidth;
                            }
                        }
                        else
                        {
                            array3[num4 * 2 + 2] = vector2 - normalized * lineWidth;
                            array3[num4 * 2 + 3] = vector2;
                        }
                    }
                    else
                    {
                        array3[num4 * 2 + 2] = vector2 - normalized * lineWidth * 0.5f;
                        array3[num4 * 2 + 3] = vector2 + normalized * lineWidth * 0.5f;
                    }
                    if (!flipY)
                    {
                        array4[num4 * 2 + 2] = new Vector2(array2[l + 1], 0f);
                        array4[num4 * 2 + 3] = new Vector2(array2[l + 1], 1f);
                    }
                    else
                    {
                        array4[num4 * 2 + 2] = new Vector2(array2[l + 1], 1f);
                        array4[num4 * 2 + 3] = new Vector2(array2[l + 1], 0f);
                    }
                }
                a = normalized;
                num4++;
            }
            Mesh mesh = new Mesh();
            mesh.vertices = array3;
            mesh.uv = array4;
            mesh.SetTriangles(array, 0);
            mesh.RecalculateBounds();
            return mesh;
        }

        public static Mesh CreateBoundMeshFromRect(Rect rc, float lineWidth, float radius, float uvScale, LineOffset Loffset = LineOffset.Centered)
        {
            Vector3[] collection = new Vector3[]
            {
                new Vector3(rc.xMin, rc.yMin, 0f),
                new Vector3(rc.xMin, rc.yMax, 0f),
                new Vector3(rc.xMax, rc.yMax, 0f),
                new Vector3(rc.xMax, rc.yMin, 0f),
                new Vector3(rc.xMin, rc.yMin, 0f)
            };
            List<Vector3> list = BMTool.MakeRound(new List<Vector3>(collection), radius);
            return BMTool.CreateLineMesh(list.ToArray(), lineWidth, uvScale, false, true, Loffset);
        }

        public static Mesh CreateBoundMeshFromBlocks(Point[] blks, float blockSize, float border, float round, float lineWidth, float lineUVScale, LineOffset outsideLineOffset, LineOffset insideLineOffset)
        {
            int num = blks.Max((Point b) => b.X) + 1;
            int num2 = blks.Max((Point b) => b.Y) + 1;
            byte[,] data = BMTool.CreateBitMapFromBlocks(blks, 1, 0, num, num2);
            byte[,] labels = new byte[num, num2];
            int num3 = BMTool.ConnectedComponentLabeling(data, labels, num, num2, true);
            List<Mesh> list = new List<Mesh>();
            Vector3 b2 = new Vector3(blockSize * 0.5f, blockSize * 0.5f, 0f);
            for (int i = 1; i <= num3; i++)
            {
                Point[] array = BMTool.CreateEdgePointsForLabel(labels, i);
                if (array != null)
                {
                    List<Vector3> list2 = new List<Vector3>();
                    for (int j = 0; j < array.Length; j++)
                    {
                        list2.Add(new Vector3((float)array[j].X * blockSize, (float)array[j].Y * blockSize, 0f) + b2);
                    }
                    list2 = BMTool.MakeRound(list2, round);
                    list.Add(BMTool.CreateLineMesh(list2.ToArray(), lineWidth, lineUVScale, false, true, outsideLineOffset));
                }
            }
            byte[,] data2 = BMTool.CreateBitMapFromBlocks(blks, 0, 1, num, num2);
            byte[,] array2 = new byte[num, num2];
            int num4 = BMTool.ConnectedComponentLabeling(data2, array2, num, num2, false);
            HashSet<int> hashSet = new HashSet<int>();
            for (int k = 0; k < num4; k++)
            {
                hashSet.Add(k + 1);
            }
            for (int l = 0; l < num2; l++)
            {
                if (hashSet.Contains((int)array2[0, l]))
                {
                    hashSet.Remove((int)array2[0, l]);
                }
                if (hashSet.Contains((int)array2[num - 1, l]))
                {
                    hashSet.Remove((int)array2[num - 1, l]);
                }
            }
            for (int m = 0; m < num; m++)
            {
                if (hashSet.Contains((int)array2[m, 0]))
                {
                    hashSet.Remove((int)array2[m, 0]);
                }
                if (hashSet.Contains((int)array2[m, num2 - 1]))
                {
                    hashSet.Remove((int)array2[m, num2 - 1]);
                }
            }
            foreach (int labelIndex in hashSet)
            {
                Point[] array3 = BMTool.CreateEdgePointsForLabel(array2, labelIndex);
                if (array3 != null)
                {
                    List<Vector3> list3 = new List<Vector3>();
                    for (int n = 0; n < array3.Length; n++)
                    {
                        list3.Add(new Vector3((float)array3[n].X * blockSize, (float)array3[n].Y * blockSize, 0f) + b2);
                    }
                    list3 = BMTool.MakeRound(list3, round);
                    list.Add(BMTool.CreateLineMesh(list3.ToArray(), lineWidth, lineUVScale, true, true, insideLineOffset));
                }
            }
            Mesh mesh = new Mesh();
            CombineInstance[] array4 = new CombineInstance[list.Count];
            for (int num5 = 0; num5 < list.Count; num5++)
            {
                array4[num5].mesh = list[num5];
                array4[num5].subMeshIndex = 0;
            }
            mesh.CombineMeshes(array4, true, false);
            mesh.RecalculateBounds();
            return mesh;
        }

        private static HashSet<byte> Get5Neighbors(byte[,] grid, Point cur)
        {
            HashSet<byte> hashSet = new HashSet<byte>();
            cur.X--;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            cur.Y++;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            cur.X++;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            cur.X++;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            return hashSet;
        }

        private static HashSet<byte> Get3Neighbors(byte[,] grid, Point cur)
        {
            HashSet<byte> hashSet = new HashSet<byte>();
            cur.X--;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            cur.Y++;
            cur.X++;
            if (BMTool.Grid(grid, cur) != 0)
            {
                hashSet.Add(grid[cur.X, cur.Y]);
            }
            return hashSet;
        }

        private static int ConnectedComponentLabeling(byte[,] data, byte[,] labels, int xmax, int ymax, bool use8Way)
        {
            Dictionary<byte, HashSet<byte>> dictionary = new Dictionary<byte, HashSet<byte>>();
            byte b = 1;
            for (int i = ymax - 1; i >= 0; i--)
            {
                for (int j = 0; j < xmax; j++)
                {
                    if (data[j, i] != 0)
                    {
                        HashSet<byte> hashSet;
                        if (use8Way)
                        {
                            hashSet = BMTool.Get5Neighbors(labels, new Point(j, i));
                        }
                        else
                        {
                            hashSet = BMTool.Get3Neighbors(labels, new Point(j, i));
                        }
                        byte b2;
                        if (hashSet.Count == 0)
                        {
                            b2 = b;
                            dictionary.Add(b2, new HashSet<byte>
                            {
                                b2
                            });
                            b += 1;
                        }
                        else
                        {
                            b2 = hashSet.Min<byte>();
                            foreach (byte key in hashSet)
                            {
                                dictionary[key].UnionWith(hashSet);
                            }
                        }
                        labels[j, i] = b2;
                    }
                }
            }
            foreach (byte b3 in dictionary.Keys)
            {
                foreach (byte b4 in dictionary[b3])
                {
                    if (b3 != b4)
                    {
                        dictionary[b4].UnionWith(dictionary[b3]);
                    }
                }
            }
            int num = 0;
            for (int k = ymax - 1; k >= 0; k--)
            {
                for (int l = 0; l < xmax; l++)
                {
                    byte b5 = labels[l, k];
                    if (b5 != 0)
                    {
                        labels[l, k] = dictionary[b5].Min<byte>();
                        if ((int)labels[l, k] > num)
                        {
                            num = (int)labels[l, k];
                        }
                    }
                }
            }
            return num;
        }

        private static void Print(byte[,] board)
        {
            StringBuilder stringBuilder = new StringBuilder();
            int length = board.GetLength(1);
            int length2 = board.GetLength(0);
            for (int i = length - 1; i >= 0; i--)
            {
                for (int j = 0; j < length2; j++)
                {
                    stringBuilder.Append(board[j, i]);
                }
                stringBuilder.AppendLine();
            }
            UnityEngine.Debug.Log(stringBuilder.ToString());
        }

        private static byte[,] CreateBitMapFromBlocks(Point[] blks, byte posVal, byte negVal, int xmax, int ymax)
        {
            byte[,] array = new byte[xmax, ymax];
            for (int i = 0; i < ymax; i++)
            {
                for (int j = 0; j < xmax; j++)
                {
                    array[j, i] = negVal;
                }
            }
            foreach (Point point in blks)
            {
                array[point.X, point.Y] = posVal;
            }
            return array;
        }

        private static List<Vector3> MakeRound(List<Vector3> vec, float radius)
        {
            List<Vector3> list = new List<Vector3>();
            for (int i = 0; i < vec.Count; i++)
            {
                int index;
                int index2;
                if (i == 0)
                {
                    index = vec.Count - 2;
                    index2 = 1;
                }
                else if (i == vec.Count - 1)
                {
                    index = i - 1;
                    index2 = 1;
                }
                else
                {
                    index = i - 1;
                    index2 = i + 1;
                }
                Vector3 normalized = (vec[index] - vec[i]).normalized;
                Vector3 normalized2 = (vec[index2] - vec[i]).normalized;
                float f = Vector3.Dot(normalized, normalized2);
                if (Mathf.Abs(f) < 0.1f)
                {
                    list.Add(vec[i] + normalized * radius);
                    list.Add(vec[i] + (normalized + normalized2) * radius * 0.3f);
                    list.Add(vec[i] + normalized2 * radius);
                }
                else
                {
                    list.Add(vec[i]);
                }
            }
            return list;
        }


        private static byte Grid(byte[,] grid, Point p)
        {
            int x = p.X;
            int y = p.Y;
            int length = grid.GetLength(1);
            int length2 = grid.GetLength(0);
            return (byte)((0 <= x && x < length2 && 0 <= y && y < length) ? grid[x, y] : 0);
        }

        private static byte Grid(byte[,] grid, int x, int y)
        {
            int length = grid.GetLength(1);
            int length2 = grid.GetLength(0);
            return (byte)((0 <= x && x < length2 && 0 <= y && y < length) ? grid[x, y] : 0);
        }


        private static int MarchingSquareVal(byte[,] data, int x, int y, byte v)
        {
            int num = 0;
            if (BMTool.Grid(data, x, y) == v)
            {
                num |= 1;
            }
            if (BMTool.Grid(data, x + 1, y) == v)
            {
                num |= 2;
            }
            if (BMTool.Grid(data, x + 1, y + 1) == v)
            {
                num |= 4;
            }
            if (BMTool.Grid(data, x, y + 1) == v)
            {
                num |= 8;
            }
            return num;
        }

        private static Point FindFirstOccurance(byte[,] grid, byte val)
        {
            int length = grid.GetLength(1);
            int length2 = grid.GetLength(0);
            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < length2; j++)
                {
                    if (grid[j, i] == val)
                    {
                        return new Point(j, i);
                    }
                }
            }
            return new Point(-1, -1);
        }

        private static Point[] CreateEdgePointsForLabel(byte[,] labels, int labelIndex)
        {
            Point point = BMTool.FindFirstOccurance(labels, (byte)labelIndex);
            if (point.X < 0)
            {
                return null;
            }
            point.X--;
            point.Y--;
            int x = point.X;
            int y = point.Y;
            int num = BMTool.MarchingSquareVal(labels, point.X, point.Y, (byte)labelIndex);
            if (num == 0 || num == 15)
            {
                UnityEngine.Debug.LogError(string.Concat(new object[]
                {
                    "CreateBoundMeshFromBlocks initialVal(",
                    num,
                    ") is out of range ",
                    point
                }));
                return null;
            }
            List<Point> list = new List<Point>();
            list.Add(point);
            int num2 = -1;
            int num3;
            for (; ; )
            {
                num3 = BMTool.MarchingSquareVal(labels, point.X, point.Y, (byte)labelIndex);
                int num4;
                switch (num3)
                {
                    case 1:
                    case 3:
                    case 7:
                        num4 = 3;
                        goto IL_192;
                    case 2:
                    case 6:
                    case 14:
                        num4 = 2;
                        goto IL_192;
                    case 4:
                    case 12:
                    case 13:
                        num4 = 1;
                        goto IL_192;
                    case 5:
                        num4 = ((num2 != 0) ? 3 : 1);
                        goto IL_192;
                    case 8:
                    case 9:
                    case 11:
                        num4 = 0;
                        goto IL_192;
                    case 10:
                        num4 = ((num2 != 3) ? 2 : 0);
                        goto IL_192;
                }
                break;
                IL_192:
                switch (num4)
                {
                    case 0:
                        point.Y++;
                        break;
                    case 1:
                        point.X++;
                        break;
                    case 2:
                        point.Y--;
                        break;
                    case 3:
                        point.X--;
                        break;
                }
                list.Add(point);
                num2 = num4;
                if (x == point.X && y == point.Y)
                {
                    goto Block_8;
                }
            }
            UnityEngine.Debug.LogError(string.Concat(new object[]
            {
                "CreateBoundMeshFromBlocks MarchingSquareVal for ",
                point,
                " is ",
                num3
            }));
            return null;
            Block_8:
            return list.ToArray();
        }

        public static bool UseSeed { get; set; }

        public static int Seed
        {
            get
            {
                return BMTool.seed;
            }
            set
            {
                BMTool.UseSeed = true;
                BMTool.seed = value;
            }
        }

        public static int Rand(int min, int max)
        {
            if (!BMTool.UseSeed)
            {
                return UnityEngine.Random.Range(min, max);
            }
            Debugger.Assert(min <= max, "BMTool.Rand - Min can not be larger than the Max.");
            if (min == max)
            {
                return min;
            }
            return BMTool.MS_Rand(ref BMTool.seed) % (max - min) + min;
        }

        public static int MS_Rand(ref int _seed)
        {
            _seed = _seed * 214013 + 2531011;
            return _seed >> 16 & 32767;
        }

        public static void ExecuteForEachRandomIndex(int beginIndex, int endIndex, Func<int, bool> action)
        {
            Debugger.Assert(beginIndex >= 0 && endIndex >= beginIndex, "ExecuteOfEachRandomIndex - Index bigger than zero. Begin index bigger than end index.");
            List<int> list = new List<int>();
            for (int i = beginIndex; i <= endIndex; i++)
            {
                list.Add(i);
            }
            bool flag = true;
            while (list.Count > 0 && flag)
            {
                int index = UnityEngine.Random.Range(0, list.Count);
                flag = action(list[index]);
                list.RemoveAt(index);
            }
        }

        public static int GetUniqueIndex(int max)
        {
            string adid = Profile.ADID;
            byte[] bytes = Encoding.ASCII.GetBytes(adid);
            int num = 0;
            foreach (byte b in bytes)
            {
                num += (int)b;
            }
            return num % max;
        }

        public static Texture2D CreateDummyTexture(int width, int height, Color color)
        {
            Texture2D texture2D = new Texture2D(width, height);
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    texture2D.SetPixel(j, i, color);
                }
            }
            texture2D.Apply();
            return texture2D;
        }

        public static Vector2 GetScreenPixelSize()
        {
            return new Vector2((float)Screen.width, (float)Screen.height);
        }

        public static Image MakeGUITexture(Texture2D tex, float screenScaleHeight)
        {
            Image guitexture = GameObjectExt.CreateTemporaryGameObjectWithComponent<Image>();
            Vector2 screenPixelSize = BMTool.GetScreenPixelSize();
            float num = screenPixelSize.y / screenPixelSize.x;
            float num2 = (float)tex.width / (float)tex.height;
            Vector3 vector = new Vector3(screenScaleHeight * num2 * num, screenScaleHeight, 1f);
            guitexture.transform.localScale = vector;
            guitexture.transform.position = vector / 2f;
         ;
            return guitexture;
        }

        public static void MergeTexture2D(this Texture2D _this, IEnumerable<Texture2D> textures, int xCount, int yCount)
        {
            Debugger.Assert(_this != null);
            Debugger.Assert(textures != null);
            int width = _this.width;
            int height = _this.height;
            Color32[] array = new Color32[width * height];
            int num = 0;
            int num2 = 0;
            foreach (Texture2D texture2D in textures)
            {
                Rect rect = new Rect(0f, 0f, (float)(width / xCount), (float)(height / yCount));
                rect.x = (float)num * rect.width;
                rect.y = (float)(yCount - num2 - 1) * rect.height;
                num++;
                if (num >= xCount)
                {
                    num2++;
                    num = 0;
                }
                Color32[] pixels = texture2D.GetPixels32();
                int width2 = texture2D.width;
                int height2 = texture2D.height;
                int num3 = 0;
                while ((float)num3 < rect.height)
                {
                    int num4 = 0;
                    while ((float)num4 < rect.width)
                    {
                        int num5 = (int)((float)(num4 * width2) / rect.width);
                        int num6 = (int)((float)(num3 * height2) / rect.height);
                        array[(int)((float)num4 + rect.x + ((float)num3 + rect.y) * (float)width)] = pixels[num5 + num6 * width2];
                        num4++;
                    }
                    num3++;
                }
            }
            _this.SetPixels32(array);
            _this.Apply();
        }

        public static void ConvertToNonTransparent(this Texture2D _this)
        {
            Debugger.Assert(_this != null);
            Color32[] pixels = _this.GetPixels32();
            for (int i = 0; i < pixels.Length; i++)
            {
                pixels[i].a = byte.MaxValue;
            }
            _this.SetPixels32(pixels);
            _this.Apply();
        }

        public static Color32 UIntToColor(uint color)
        {
            byte a = (byte)(color >> 24);
            byte r = (byte)(color >> 16);
            byte g = (byte)(color >> 8);
            byte b = (byte)(color >> 0);
            return new Color32(r, g, b, a);
        }

        public static uint ColorToUInt(Color32 color)
        {
            return (uint)((int)color.a << 24 | (int)color.r << 16 | (int)color.g << 8 | (int)color.b << 0);
        }

        private static int seed;
    }
}
